package spring.cloud.tasks.executor.name_space.executor;

import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.HostUtil;
import spring.cloud.tasks.executor.name_space.NameSpaceDataManager;
import spring.cloud.tasks.executor.utils.LogUtils;
import spring.cloud.tasks.executor.utils.SystemEnvProperties;

@Slf4j
@Setter
@Getter

public class ExecutorInitAndTaskInitService {
    public static final int WAIT_JOBCLASS_ADDED_COUNT = 25;
    private static final int WAIT_FOR_IP_NODE_DISAPPEAR_COUNT = 150;
    private String executorId;
    private NameSpaceDataManager nameSpaceDataManager;
    private String executorIpNodePath;
    //
    private TaskInitService taskInitService;

    public ExecutorInitAndTaskInitService(@NonNull String executorId, NameSpaceDataManager nameSpaceDataManager) {
        this.executorId = executorId;
        this.nameSpaceDataManager = nameSpaceDataManager;
        nameSpaceDataManager.setExecutorId(executorId);
    }
    //##<!-我是优美的功能模块分割线->##

    /**
     * 注册Executor
     */
    public void registerExecutor() throws Exception {
        checkExecutorExists();
        setExecutorInfo();
    }

    /**
     * 启动前先检查本机与注册中心的时间误差秒数是否在允许范围和Executor是否已启用
     */
    private void checkExecutorExists() throws Exception {
        // 启动时检查本机与注册中心的时间误差秒数是否在允许范围
        String executorNodePath = ExecutorsNode.EXECUTORS_ROOT + "/" + executorId;
        try {
            long timeDiff = Math.abs(System.currentTimeMillis() - nameSpaceDataManager.getCtime(executorNodePath + "/systemTime/current"));
            int maxTimeDiffSeconds = 60;
            if (timeDiff > maxTimeDiffSeconds * 1000L) {
                Long timeDiffSeconds = Long.valueOf(timeDiff / 1000);
                throw new RuntimeException(timeDiffSeconds.intValue() + maxTimeDiffSeconds + "");
            }
        } finally {
            String executorSystemTimePath = executorNodePath + "/systemTime/current";
            if (nameSpaceDataManager.checkExists(executorSystemTimePath)) {
                nameSpaceDataManager.delete(executorSystemTimePath);
            }
        }
        // 启动时检查Executor是否已启用（ExecutorName为判断的唯一标识）
        if (!nameSpaceDataManager.checkExists(executorNodePath)) {
            nameSpaceDataManager.createIfNeedOrSetData(executorNodePath, "");
        } else {
            int count = 0;
            do {
                if (!nameSpaceDataManager.checkExists(executorNodePath + "/ip")) {
                    return;
                }
                LogUtils.warn(log, "", "{}/ip node found. Try to sleep and wait for this node disappear.", executorNodePath);
                Thread.sleep(100L);
            } while (++count <= WAIT_FOR_IP_NODE_DISAPPEAR_COUNT);
            throw new Exception("The executor (" + executorId + ") is running, cannot running the instance twice.");
        }
    }

    private void setExecutorInfo() throws Exception {
        String executorNodePath = ExecutorsNode.EXECUTORS_ROOT + "/" + executorId;
        executorIpNodePath = executorNodePath + "/ip";
        // 持久化ip
        nameSpaceDataManager.createEphemeralDataNode(executorIpNodePath, HostUtil.cachedIpAddress);
        // 持久化最近启动时间
        String lastBeginTimeNodePath = executorNodePath + "/lastBeginTime";
        nameSpaceDataManager.createIfNeedOrSetData(lastBeginTimeNodePath, String.valueOf(System.currentTimeMillis()));
        // 持久化clean Executor离线时，其zk节点信息是否被清理
        String executorCleanNodePath = executorNodePath + "/clean";
        nameSpaceDataManager.createIfNeedOrSetData(executorCleanNodePath, String.valueOf(SystemEnvProperties.EXECUTOR_CLEAN));


    }


    /**
     * 注销Executor
     */
    public void unRegisterExecutor() {
        removeExecutorIpNode();
    }

    private void removeExecutorIpNode() {
        try {
            if (nameSpaceDataManager != null && executorIpNodePath != null && nameSpaceDataManager.isConnected()) {
                LogUtils.info(log, "", "{} is going to delete its ip node {}", executorId, executorIpNodePath);
                nameSpaceDataManager.delete(executorIpNodePath);
            }
        } catch (Throwable t) {
            LogUtils.error(log, "", t.toString(), t);
        }
    }
    //##<!-我是优美的功能模块分割线->##

    /**
     * 注册$/Jobs的watcher，响应添加任务的事件，初始化任务。注意，会响应已经存在的任务。
     */
    public void registerTaskWatcher() throws Exception {
        if (taskInitService != null) {
            taskInitService.shutdown();
        }
        taskInitService = new TaskInitService(this);
        taskInitService.start();
    }

    /**
     * 销毁监听添加任务的watcher。关闭正在初始化任务的线程，直到其结束。
     */
    public void unRegisterTaskWatcher() {
        if (taskInitService != null) {
            taskInitService.shutdown();
        }
    }


}
